/**
 * 
 */
package cn.edu.ustc.multicore.exercise.ch5;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;

import cn.edu.ustc.multicore.exercise.ch1.PrimeSearching;

/**
 * @author dragon
 * 
 */
public class ReadWriteLockTest {
	private ReadWriteLock mutex = null;
	private int readers;
	private int writers;

	public ReadWriteLockTest(ReadWriteLock lock, int readers, int writers) {
		this.mutex = lock;
		this.readers = readers;
		this.writers = writers;
	}

	public void run() {
		String text = null;
		for (int i = 0; i < writers; i++) {
			// write
			mutex.writeLock().lock();
			try {
				text = "hello,world";
				CriticalSection.getInstance().write(text);
			} finally {
				mutex.writeLock().unlock();
			}
		}

		for (int i = 0; i < readers; i++) {
			// read
			mutex.readLock().lock();
			try {
				text = CriticalSection.getInstance().read();
			} finally {
				mutex.readLock().unlock();
			}
		}

	}

	static class Writer extends Thread {
		Lock mutex;

		public Writer(Lock lock) {
			this.mutex = lock;
		}

		public void run() {
			String text = null;
			// write
			mutex.lock();
			try {
				text = "hello,world";
				CriticalSection.getInstance().write(text);
			} finally {
				mutex.unlock();
			}
		}
	}

	static class Reader extends Thread {
		Lock mutex;

		public Reader(Lock lock) {
			this.mutex = lock;
		}

		public void run() {
			String text = null;
			// read
			mutex.lock();
			try {
				text = CriticalSection.getInstance().read();
			} finally {
				mutex.unlock();
			}
		}

	}

	public static void test(int rnum, int wnum, ReadWriteLock lock) {
		long startTime = 0l;
		long endTime = 0l;
		double usedSecond = 0.0;
		try {
			startTime = System.currentTimeMillis();
			Reader[] readers = new Reader[rnum];
			Writer[] writers = new Writer[wnum];

			for (int i = 0; i < rnum; i++) {
				readers[i] = new Reader(lock.readLock());
				readers[i].start();
			}
			for (int i = 0; i < wnum; i++) {
				writers[i] = new Writer(lock.writeLock());
				writers[i].start();
			}

			for (int i = 0; i < rnum; i++) {
				readers[i].join();
			}

			for (int i = 0; i < wnum; i++) {
				writers[i].join();
			}

			endTime = System.currentTimeMillis();
			usedSecond = (double) (endTime - startTime) / 1000;
			printResult(lock.getClass().getName(), rnum, wnum, CriticalSection
					.getInstance(), usedSecond);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public static void printResult(String program, int readers, int writers,
			CriticalSection critical, double usedTime) {
		System.out.println("the result of lock performance as below: ");
		System.out.println("---------------------------------------");
		System.out.println("-> used lock: " + program);
		System.out.println("-> used reader number: " + readers);
		System.out.println("-> used writer number: " + writers);
		System.out.println("-> read times: " + critical.getReadTimes());
		System.out.println("-> write times: " + critical.getWriteTimes());
		System.out.println("-> used time(s): " + usedTime);
		System.out.println("---------------------------------------\n\n");
	}

	public static void main(String[] args) {
		int readers = 1000;
		int writers = 10;
		// parse the parameter, and assign them
		if (args != null & args.length > 0) {
			boolean correct = true;
			for (int i = 0; i < args.length; i++) {
				if ("-readers".equals(args[i])) {
					if (args[i + 1] != null) {
						readers = Integer.valueOf(args[i + 1]);
						i++;
						continue;
					} else {
						correct = false;
						break;
					}
				}
				if ("-writers".equals(args[i])) {
					if (args[i + 1] != null) {
						writers = Integer.valueOf(args[i + 1]);
						i++;
						continue;
					} else {
						correct = false;
						break;
					}
				}
				if (!correct) {
					System.out.println("Usage: "
							+ PrimeSearching.class.getName()
							+ " -threads number");
					return;
				}
			}
		}
		ReadWriteLock implicit = new ImplicitSimpleReadWriteLock();
		test(readers, writers, implicit);
		ReadWriteLock simple = new SimpleReadWriteLock();
		test(readers, writers, simple);
	}
}
